package com.sun.aop.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;

import java.util.Collections;
import java.util.List;
import java.util.Map;


/**
 * @Author 喻湘东
 * @Create 2019-08-27 11:42:05
 */
@Component
@Slf4j
public class RedisUtil {

    private static final String LOCK_SUCCESS = "OK";
    private static final String RELEASE_SUCCESS = "1";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";


    @Autowired
    private JedisPool jedisPool;


    private Jedis getJedis() {
        return jedisPool.getResource();
    }

    /**
     * 设值
     *
     * @param key
     * @param value
     * @return
     */
    public String set(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.set(key, value);
        } catch (Exception e) {
            log.error("set key:{} value:{} error", key, value, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 设值
     *
     * @param key
     * @param value
     * @param expireTime 过期时间, 单位: s
     * @return
     */
    public String set(String key, String value, int expireTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.setex(key, expireTime, value);
        } catch (Exception e) {
            log.error("set key:{} value:{} expireTime:{} error", key, value, expireTime, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 取值
     *
     * @param key
     * @return
     */
    public String get(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.get(key);
        } catch (Exception e) {
            log.error("get key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 删除key
     *
     * @param key
     * @return
     */
    public Long del(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.del(key.getBytes());
        } catch (Exception e) {
            log.error("del key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 判断key是否存在
     *
     * @param key
     * @return
     */
    public Boolean exists(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.exists(key.getBytes());
        } catch (Exception e) {
            log.error("exists key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 设值key过期时间
     *
     * @param key
     * @param expireTime 过期时间, 单位: s
     * @return
     */
    public Long expire(String key, int expireTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.expire(key.getBytes(), expireTime);
        } catch (Exception e) {
            log.error("expire key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 获取剩余时间
     *
     * @param key
     * @return
     */
    public Long ttl(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.ttl(key);
        } catch (Exception e) {
            log.error("ttl key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    private void close(Jedis jedis) {
        if (null != jedis) {
            jedis.close();
        }
    }




    /**
     *
     * @param key
     * @param value
     * @param expireTime  时间单位：秒
     * @return 是否成功加锁
     */
    public boolean tryLock(final String key, final String value, final int expireTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();

            if(jedis.setnx(key,value)==1){
                if(expireTime>0){
                    jedis.expire(key,expireTime);
                }
                return true;
            }else {
                System.out.println(Thread.currentThread().getName()+" 未获取到锁");
                return false;
            }

            /*String result = null;

            if(expireTime!=null && expireTime>0){

                result = jedis.set(key, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime*1000);
            }else{
                result = jedis.set(key, value, SET_IF_NOT_EXIST);
            }

            if(LOCK_SUCCESS.equals(result)){
                return true;
            }else {
                System.out.println(Thread.currentThread().getName()+" 未获取到锁");
            }*/
        } catch (Exception e) {
            log.error("set key:{} error", key, e);
            return false;
        } finally {
            close(jedis);
        }
    }

    /**
     *
     * @param key
     * @param value
     * @return 是否成功解锁
     */
    public boolean unLock(String key, String value) {

        if (!exists(key)){
            return true;
        }

        Jedis jedis = null;
        try {
            jedis = getJedis();
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(key), Collections.singletonList(value));
            if(RELEASE_SUCCESS.equals(String.valueOf(result))){
                return true;
            }
        } catch (Exception e) {
            log.error("del key:{} error", key, e);
            return false;
        } finally {
            close(jedis);
        }
        return false;
    }

    /**
     * 获取管道流对象
     * @return
     */
    public Pipeline getPipeline(){
        return getJedis().pipelined();
    }


    public void hmset(String key, Map<String,String> value,int seconds){
        Jedis jedis = getJedis();
        try{
            String hmset = jedis.hmset(key, value);
            if(seconds>0){
                jedis.expire(key,seconds);
            }
        }finally {
            close(jedis);
        }

    }

    public List<String> hmget(String key, String ... value){

        Jedis jedis = getJedis();
        try{
            return jedis.hmget(key, value);
        }finally {
            close(jedis);
        }


    }

    public Map<String, String> hmgetAll(String key){

        Jedis jedis = getJedis();
        try{
            return jedis.hgetAll(key);
        }finally {
            close(jedis);
        }


    }

    public void lpush(String key,int seconds, String ... value){
        Jedis jedis = getJedis();
        try{
            Long lpush = jedis.lpush(key, value);
            if(seconds>0){
                jedis.expire(key,seconds);
            }
        }finally {
            close(jedis);
        }

    }
    public void rpush(String key,int seconds, String ... value){
        Jedis jedis = getJedis();
        try{
            jedis.rpush(key, value);
            if(seconds>0){
                jedis.expire(key,seconds);
            }
        }finally {
            close(jedis);
        }

    }

    public List<String> lrange(String key, int f, int l){
        Jedis jedis = getJedis();
        try{
            return jedis.lrange(key,f,l);
        }finally {
            close(jedis);
        }

    }

    public String lpop(String key){
        Jedis jedis = getJedis();
        try{
            return jedis.lpop(key);
        }finally {
            close(jedis);
        }
    }
    public String rpop(String key){
        Jedis jedis = getJedis();
        try{
            return jedis.rpop(key);
        }finally {
            close(jedis);
        }
    }
    public long llen(String key){
        Jedis jedis = getJedis();
        try{
            return jedis.llen(key);
        }finally {
            close(jedis);
        }
    }


}
